package org.vehicle.util;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URI;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class HttpClientUtil {  
	
	static int TIMEOUT = 20 * 1000;
	private static final String DEFAULT_ENCODE = "utf-8";
	private static final Integer MAXTOTAL = 200;
	private static final Integer MAXPERROUTE = 40;
	private static final Integer MAXROUTE = 100;
	private static CloseableHttpClient httpClient = null;
	private final static Object syncLock = new Object();
	 /**
	  * 配置
	  * @param httpRequestBase
	  */
	 private static void config(HttpRequestBase httpRequestBase) {
		 // 配置请求的超时设置
		 RequestConfig requestConfig = RequestConfig.custom()    
                 .setConnectTimeout(TIMEOUT).setConnectionRequestTimeout(TIMEOUT)    
                 .setSocketTimeout(TIMEOUT).build();  
		 httpRequestBase.setConfig(requestConfig);
	 }
	 
	 /**
	  * 获取HttpClient对象
	  * @param url
	  * @return
	  */
	 public static CloseableHttpClient getHttpClient(String url) {
	        String hostname = url.split("/")[2];
	        int port = 80;
	        if (hostname.contains(":")) {
	            String[] arr = hostname.split(":");
	            hostname = arr[0];
	            port = Integer.parseInt(arr[1]);
	        }
	        synchronized (syncLock) {
                if (httpClient == null) {
                    httpClient = createHttpClient(MAXTOTAL, MAXPERROUTE, MAXROUTE, hostname, port);
                }
            }
	        return httpClient;
	    }
	 
	 
	 /**
	  * 创建HttpClient对象
	  * @param maxTotal
	  * @param maxPerRoute
	  * @param maxRoute
	  * @param hostname
	  * @param port
	  * @return
	  */
	 public static CloseableHttpClient createHttpClient(int maxTotal,
	            int maxPerRoute, int maxRoute, String hostname, int port) {
		 SSLContext sslcontext = null;
		try {
			sslcontext = createIgnoreVerifySSL();
		} catch (KeyManagementException | NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
         // 设置协议http和https对应的处理socket链接工厂的对象  
         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()  
              .register("http", PlainConnectionSocketFactory.INSTANCE)  
              .register("https", new SSLConnectionSocketFactory(sslcontext))  
              .build(); 
         PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
         // 将最大连接数增加
         connManager.setMaxTotal(maxTotal);
         // 将每个路由基础的连接增加
         connManager.setDefaultMaxPerRoute(maxPerRoute);
         HttpHost httpHost = new HttpHost(hostname, port);
         // 将目标主机的最大连接数增加
         connManager.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
         // 请求重试处理
         HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
             public boolean retryRequest(IOException exception,
                     int executionCount, HttpContext context) {
                 if (executionCount >= 5) {// 如果已经重试了5次，就放弃
                     return false;
                 }
                 if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                     return true;
                 }
                 if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                     return false;
                 }
                 if (exception instanceof InterruptedIOException) {// 超时
                     return false;
                 }
                 if (exception instanceof UnknownHostException) {// 目标服务器不可达
                     return false;
                 }
                 if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                     return false;
                 }
                 if (exception instanceof SSLException) {// SSL握手异常
                     return false;
                 }

                 HttpClientContext clientContext = HttpClientContext
                         .adapt(context);
                 HttpRequest request = clientContext.getRequest();
                 // 如果请求是幂等的，就再次尝试
                 if (!(request instanceof HttpEntityEnclosingRequest)) {
                     return true;
                 }
                 return false;
             }
         };
         CloseableHttpClient httpClient = HttpClients.custom()
                 .setConnectionManager(connManager)
                 .setRetryHandler(httpRequestRetryHandler).build();
         return httpClient;
	 }
	
	
	/** 
     * 绕过验证 
     * @return 
     * @throws NoSuchAlgorithmException  
     * @throws KeyManagementException  
     */  
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {  
        SSLContext sc = SSLContext.getInstance("SSLv3");  
      
        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法  
        X509TrustManager trustManager = new X509TrustManager() {  
            @Override  
            public void checkClientTrusted(  
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
                    String paramString) {  
            }  
            @Override  
            public void checkServerTrusted(  
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
                    String paramString) {  
            }  
            @Override  
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
                return null;  
            }  
        };  
      
        sc.init(null, new TrustManager[] { trustManager }, null);  
        return sc;  
    }
	
	/**
	 * 发送有参get请求
	 * @param url
	 * @param param
	 * @return
	 */
    public static String doGet(String url, Map<String, String> param) {  
        // 创建Httpclient对象  
        CloseableHttpClient httpclient = getHttpClient(url);
        String resultString = "";  
        CloseableHttpResponse response = null;  
        try {  
            // 创建uri  
            URIBuilder builder = new URIBuilder(url);  
            if (param != null) {  
                for (String key : param.keySet()) {  
                    builder.addParameter(key, param.get(key));  
                }  
            }  
            URI uri = builder.build();  
  
            // 创建http GET请求  
            HttpGet httpGet = new HttpGet(uri); 
            config(httpGet);
            // 执行请求  
            response = httpclient.execute(httpGet);  
            System.out.println(response.getStatusLine().getStatusCode());
            // 判断返回状态是否为200  
            if (response.getStatusLine().getStatusCode() == 200) {  
                resultString = EntityUtils.toString(response.getEntity(), DEFAULT_ENCODE);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                if (response != null) {  
                    response.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        return resultString;  
    }  
    /**
	 * 发送无参get请求
	 * @param url
	 * @param param
	 * @return
	 */
    public static String doGet(String url) {  
        return doGet(url, null);  
    }  
    /**
     * 发送form表单数据post请求
     * @param url
     * @param param
     * @return
     */
    public static String doPost(String url, Map<String, String> param) {  
        // 创建Httpclient对象  
        CloseableHttpClient httpClient = getHttpClient(url);
        CloseableHttpResponse response = null;  
        String resultString = "";  
        try {  
            // 创建Http Post请求  
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表  
            if (param != null) {  
                List<NameValuePair> paramList = new ArrayList<NameValuePair>();  
                for (String key : param.keySet()) {  
                    paramList.add(new BasicNameValuePair(key, param.get(key)));  
                }  
                config(httpPost);
                // 模拟表单  
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,DEFAULT_ENCODE); 
                httpPost.setEntity(entity);
            }  
            // 执行http请求  
            response = httpClient.execute(httpPost);  
            resultString = EntityUtils.toString(response.getEntity(), DEFAULT_ENCODE);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                response.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
  
        return resultString;  
    }  
    /**
     * 发送无参post请求
     * @param url
     * @return
     */
    public static String doPost(String url) {  
        return doPost(url, null);  
    }  
    /**
     * 发送json数据post请求
     * @param url
     * @param json
     * @return
     */
    public static String doPostJson(String url, String json) {  
        // 创建Httpclient对象  
        CloseableHttpClient httpClient = getHttpClient(url);
        CloseableHttpResponse response = null;  
        String resultString = "";  
        try {  
            // 创建Http Post请求  
            HttpPost httpPost = new HttpPost(url);  
            config(httpPost);
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
            httpPost.setHeader("Connection", "close");
            // 创建请求内容  
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);  
            httpPost.setEntity(entity);  
            // 执行http请求  
            response = httpClient.execute(httpPost);  
            resultString = EntityUtils.toString(response.getEntity(), DEFAULT_ENCODE);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                response.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        return resultString;  
    }
    
    /**
	 * 获取微信图片
	 * @param url
	 * @param param
	 * @return
	 */
    public static byte[] doInputStreamGet(String url) {  
        // 创建Httpclient对象  
        CloseableHttpClient httpclient = getHttpClient(url);
        byte[] data = null;  
        CloseableHttpResponse response = null;  
        try {  
            // 创建http GET请求  
            HttpGet httpGet = new HttpGet(url); 
            config(httpGet);
            // 执行请求  
            response = httpclient.execute(httpGet);  
            // 判断返回状态是否为200  
            if (response.getStatusLine().getStatusCode() == 200) {  
            	System.out.println(response.getEntity());
            	return EntityUtils.toByteArray(response.getEntity());
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                if (response != null) {  
                    response.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        return data;  
    }  
}  